﻿namespace Silverlight.Treemap
{
    using System.Collections;
    using System.Collections.Generic;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;

    using Extensions;

    [TemplatePart(Name = WorkAreaName, Type = typeof(Canvas))]
    [StyleTypedProperty(Property = "ChartAreaStyle", StyleTargetType = typeof(Canvas))]
    public class Chart : Control, IGetTemplateChild
    {
        #region public Style ChartAreaStyle

        /// <summary>
        /// Identifies the ChartAreaStyle dependency property.
        /// </summary>
        public static readonly DependencyProperty ChartAreaStyleProperty = DependencyProperty.Register(
                "ChartAreaStyle", typeof(Style), typeof(Chart), null);

        /// <summary>
        /// Gets or sets the Style of the ISeriesHost's ChartArea.
        /// </summary>
        public Style ChartAreaStyle
        {
            get { return this.GetValue(ChartAreaStyleProperty) as Style; }
            set { this.SetValue(ChartAreaStyleProperty, value); }
        }

        #endregion public Style ChartAreaStyle

        private const string WorkAreaName = "WorkArea";

        /// <summary>
        /// Identifies the ItemsSource dependency property.
        /// </summary>
        public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register(
                "ItemsSource", typeof(IEnumerable), typeof(Chart), new PropertyMetadata(OnItemsSourceChanged));

        private Canvas workAreaCanvas;
        private Size currentSize;

        public Chart()
        {
            this.DefaultStyleKey = typeof(Chart);
        }

        /// <summary>
        /// Gets or sets the Binding instance to use for the DependentValue.
        /// </summary>
        public Binding DependentValueBinding
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the Binding instance to use for the IndependentValue.
        /// </summary>
        public Binding IndependentValueBinding
        {
            get;
            set;
        }

        public Binding ChildItemsSourceBinding
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets a collection used to contain the data points of the Series.
        /// </summary>
        public IEnumerable ItemsSource
        {
            get { return (IEnumerable)this.GetValue(ItemsSourceProperty); }
            set { this.SetValue(ItemsSourceProperty, value); }
        }

        #region IGetTemplateChild Members

        public DependencyObject GetTemplateChildHelper(string childName)
        {
            return this.GetTemplateChild(childName);
        }

        #endregion

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            this.workAreaCanvas = this.GetTemplateChild<Canvas>(WorkAreaName);
            this.workAreaCanvas.SizeChanged += this.WorkAreaCanvas_OnSizeChanged;
        }

        private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((Chart)d).DataBind();
        }

        private void WorkAreaCanvas_OnSizeChanged(object sender, SizeChangedEventArgs e)
        {
            this.currentSize = e.NewSize;

            if (this.ItemsSource == null)
            {
                return;
            }

            var chartSectors = new List<ChartSector>();

            foreach (object item in this.ItemsSource)
            {
                chartSectors.Add(this.CreateChartSector(item));
            }

            List<ChartSector> sectors = Plotter.Plot(chartSectors, e.NewSize);
            this.workAreaCanvas.Children.Clear();

            foreach (ChartSector chartSector in sectors)
            {
                this.workAreaCanvas.Children.Add(chartSector);
            }
        }

        private ChartSector CreateChartSector(object item)
        {
            var chartSector = new ChartSector {DataContext = item};
            chartSector.SetBinding(ChartSector.IndependentValueProperty, this.IndependentValueBinding);
            chartSector.SetBinding(ChartSector.DependentValueProperty, this.DependentValueBinding);

            if (this.ChildItemsSourceBinding != null)
            {
                chartSector.SetBinding(ChartSector.ChildItemsSourceProperty, this.ChildItemsSourceBinding);

                if (chartSector.ChildItemsSource != null)
                {
                    foreach (object childItem in chartSector.ChildItemsSource)
                    {
                        ChartSector cs = this.CreateChartSector(childItem);
                        chartSector.ChildChartSectors.Add(cs);
                    }
                }
            }

            return chartSector;
        }

        private void DataBind()
        {
            if (this.ItemsSource == null)
            {
                return;
            }

            if (this.workAreaCanvas == null)
            {
                return;
            }

            var chartSectors = new List<ChartSector>();

            foreach (object item in this.ItemsSource)
            {
                chartSectors.Add(this.CreateChartSector(item));
            }

            //this is not nice as here we are setting the area to a default value, this needs to be refactored into a DP....
            List<ChartSector> sectors = Plotter.Plot(chartSectors, this.currentSize);
            this.workAreaCanvas.Children.Clear();

            foreach (ChartSector chartSector in sectors)
            {
                this.workAreaCanvas.Children.Add(chartSector);
            }
        }
    }
}